From c039c43debb08c4d46051a4ee4f88b461a3d47a2 Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Thu, 24 Nov 2005 19:53:09 +0000 Subject: [PATCH] Added a count of the number of users of this block device, and refuse to close down the frontend until that number becomes 0. There are no reasonable semantics for hot-unplugging a block device beneath a mounted filesystem, and this solution ensures that the guest is not crashed nor the filesystem corruptedby the actions of the administrator. Signed-off-by: Ewan Mellor --- .../drivers/xen/blkfront/blkfront.c | 30 ++++++++++++++++++- .../drivers/xen/blkfront/block.h | 6 ++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c index cab043c15c..f204629f4d 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c @@ -117,6 +117,8 @@ static int blkfront_probe(struct xenbus_device *dev, info->shadow[i].req.id = i+1; info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; + info->users = 0; + /* Front end dir is a number, which is used as the id. */ info->handle = simple_strtoul(strrchr(dev->nodename,'/')+1, NULL, 0); dev->data = info; @@ -265,6 +267,7 @@ static void backend_changed(struct xenbus_device *dev, XenbusState backend_state) { struct blkfront_info *info = dev->data; + struct block_device *bd; DPRINTK("blkfront:backend_changed.\n"); @@ -281,7 +284,18 @@ static void backend_changed(struct xenbus_device *dev, break; case XenbusStateClosing: - blkfront_closing(dev); + bd = bdget(info->dev); + if (bd == NULL) + xenbus_dev_fatal(dev, -ENODEV, "bdget failed"); + + down(&bd->bd_sem); + if (info->users > 0) + xenbus_dev_error(dev, -EBUSY, + "Device in use; refusing to close"); + else + blkfront_closing(dev); + up(&bd->bd_sem); + bdput(bd); break; } } @@ -414,12 +428,26 @@ static void blkif_restart_queue_callback(void *arg) int blkif_open(struct inode *inode, struct file *filep) { + struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; + info->users++; return 0; } int blkif_release(struct inode *inode, struct file *filep) { + struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; + info->users--; + if (info->users == 0) { + /* Check whether we have been instructed to close. We will + have ignored this request initially, as the device was + still mounted. */ + struct xenbus_device * dev = info->xbdev; + XenbusState state = xenbus_read_driver_state(dev->otherend); + + if (state == XenbusStateClosing) + blkfront_closing(dev); + } return 0; } diff --git a/linux-2.6-xen-sparse/drivers/xen/blkfront/block.h b/linux-2.6-xen-sparse/drivers/xen/blkfront/block.h index 35f1440388..809451aec7 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkfront/block.h +++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/block.h @@ -127,6 +127,12 @@ struct blkfront_info struct gnttab_free_callback callback; struct blk_shadow shadow[BLK_RING_SIZE]; unsigned long shadow_free; + + /** + * The number of people holding this device open. We won't allow a + * hot-unplug unless this is 0. + */ + int users; }; extern spinlock_t blkif_io_lock; -- 2.30.2